package com.anlogic.sdk.bsp.model;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Map;
import java.util.Properties;

import org.apache.logging.log4j.Logger;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;

import com.anlogic.sdk.utils.LogUtils;

public class PlatformProject implements IPlatformProject {
	private static Logger logger = LogUtils.getLogger(PlatformProject.class);
	
	private IProject iProject;

	public static final String PROPERTY_META_FILE_NAME = ".PlatformProject";
	public static final String PROPERTY_PROJECT_NAME = "PROJECT_NAME";
	public static final String PROPERTY_PROJECT_LOC = "PROJECT_LOCATION";
	public static final String PROPERTY_CHIP = "CHIP";
	public static final String PROPERTY_PROCESSOR = "PROCESSOR";
	public static final String PROPERTY_OS = "OS";
	private static final String PROPERTY_MSS_FILE_NAME = "MSS_FILE";
	private static final String DEFAULT_MSS_FILE_NAME = "system.mss";
	private static final String PROPERTY_HPF_FILE_NAME = "HPF_FILE";

	private String chip;
	private String processor;
	private String os;
	private String mssFileName;
	private String hpfFileName;
	private String projLoc;

	public PlatformProject(IProject iProject) {
		this.iProject = iProject;
	}

	public static PlatformProject createPlatformProject(IProject iProject, String hpfPath, String chipName, String procName, String os) {
		PlatformProject prj = new PlatformProject(iProject);
		prj.chip = chipName;
		prj.processor = procName;
		prj.mssFileName = DEFAULT_MSS_FILE_NAME;
		prj.hpfFileName = (new File(hpfPath)).getName();
		prj.os = os;
		prj.saveMetaData();
		return prj;
	}

	public String getName() {
		return iProject.getName();
	}

	public IProject getIProject() {
		return iProject;
	}

	public String getLoc() {
		return this.iProject.getLocation().toString();
	}

	public String getChip() {
		return chip;
	}
	
	public String getProcessor() {
		return processor;
	}

	public String getOs() {
		return os;
	}

	public String getMssFileName() {
		return this.mssFileName;
	}

	public IFile getMssFile() {
		return this.iProject.getFile(this.mssFileName);
	}

	public String getMssPath() {
		return this.iProject.getFile(this.mssFileName).getLocation().toString();
	}

	public String getHpfFileName() {
		return this.hpfFileName;
	}

	public IFile getHpfFile() {
		return this.iProject.getFile(this.hpfFileName);
	}

	public void setHpfFile(String hpfFileName) {
		this.hpfFileName = hpfFileName;
	}

	public String getHpfPath() {
		return this.iProject.getFile(this.hpfFileName).getLocation().toString();
	}

	public String getProperty(Properties p, String key) {
		return p.getProperty(key);
	}

	public void setProperty(Properties p, String key, String value) {
		p.setProperty(key, value);
	}

	public Properties getProperties(String backingFileName) {
		Properties p = new Properties();
		File f = new File(this.iProject.getFile(backingFileName).getLocation().toOSString());
		try {
			if (!f.exists())
				f.createNewFile();
			BufferedReader reader = new BufferedReader(new FileReader(f));
			try {
				while (true) {
					String line = reader.readLine();
					if (line == null)
						break;
					String[] nv = line.split("=");
					if (nv.length >= 2)
						p.setProperty(nv[0], nv[1]);
				}
			} finally {
				reader.close();
			}
		} catch (IOException e) {
			logger.error("Unable to load properties file {} for project {}", backingFileName, this.iProject.getName());
		}
		return p;
	}

	public Properties getDefaultProperties() {
		Properties prjMeta = getProperties(PROPERTY_META_FILE_NAME);
		return prjMeta;
	}

	public void saveMetaData() {
		Properties prjMeta = getProperties(PROPERTY_META_FILE_NAME);
		prjMeta.setProperty(PROPERTY_PROJECT_NAME, this.getName());
		prjMeta.setProperty(PROPERTY_PROJECT_LOC, this.getLoc());
		prjMeta.setProperty(PROPERTY_CHIP, this.chip);
		prjMeta.setProperty(PROPERTY_PROCESSOR, this.processor);
		prjMeta.setProperty(PROPERTY_OS, this.os);
		prjMeta.setProperty(PROPERTY_MSS_FILE_NAME, this.mssFileName);
		prjMeta.setProperty(PROPERTY_HPF_FILE_NAME, this.hpfFileName);
		saveProperties(prjMeta);
	}

	public void restoreMetaData() {
		Properties prjMeta = getProperties(PROPERTY_META_FILE_NAME);
		this.chip = prjMeta.getProperty(PROPERTY_CHIP);
		if (this.chip == null)
			this.chip = "unknown";
		this.processor = prjMeta.getProperty(PROPERTY_PROCESSOR);
		if (this.processor == null)
			this.processor = "unknown";
		this.os = prjMeta.getProperty(PROPERTY_OS);
		if (this.os == null)
			this.os = "unknown";
		this.mssFileName = prjMeta.getProperty(PROPERTY_MSS_FILE_NAME);
		if (this.mssFileName == null)
			this.mssFileName = "unknown";
		this.hpfFileName = prjMeta.getProperty(PROPERTY_HPF_FILE_NAME);
		if (this.hpfFileName == null)
			this.hpfFileName = "unknown";
		this.projLoc = prjMeta.getProperty(PROPERTY_PROJECT_LOC);
		if (this.projLoc == null)
			this.projLoc = "unknown";
	}

	public void saveProperties(Properties p) {
		File f = new File(this.iProject.getFile(PROPERTY_META_FILE_NAME).getLocation().toOSString());
		try {
			BufferedWriter writer = new BufferedWriter(new FileWriter(f.getAbsolutePath()));
			try {
				for (Map.Entry<Object, Object> entry : p.entrySet()) {
					Object k = entry.getKey();
					Object v = entry.getValue();
					writer.write(k + "=" + v + "\n");
				}
			} finally {
				writer.close();
			}
		} catch (IOException e) {
			logger.error("Unable to save properties for Project {}", this.iProject.getName());
		}
	}

	public void writeToFile(String fileName, String txt) {
		File f = new File(this.iProject.getFile(fileName).getLocation().toOSString());
		try {
			BufferedWriter writer = new BufferedWriter(new FileWriter(f.getAbsolutePath()));
			try {
				writer.write(txt);
			} finally {
				writer.close();
			}
		} catch (IOException e) {
			logger.error("Unable to save file for Project {}", this.iProject.getName());
		}
	}

	public void refreshLocal(IProgressMonitor monitor) {
		try {
			iProject.refreshLocal(2, monitor);
		} catch (CoreException e) {
			logger.error("Unable to refresh Project {}", this.iProject.getName());
		}
	}
}
